package cn.tedu.csmall.passport.service.impl;

import com.example.csmall.commons.ex.ServiceException;
import cn.tedu.csmall.passport.mapper.AdminMapper;
import cn.tedu.csmall.passport.mapper.AdminRoleMapper;
import cn.tedu.csmall.passport.mapper.LoginLogMapper;
import cn.tedu.csmall.passport.pojo.entity.Admin;
import cn.tedu.csmall.passport.pojo.entity.AdminRole;
import cn.tedu.csmall.passport.pojo.entity.LoginLog;
import cn.tedu.csmall.passport.pojo.param.AdminAddNewParam;
import cn.tedu.csmall.passport.pojo.param.AdminLoginInfoParam;
import cn.tedu.csmall.passport.pojo.param.AdminUpdateInfoParam;
import cn.tedu.csmall.passport.pojo.vo.AdminListItemVO;
import cn.tedu.csmall.passport.pojo.vo.AdminStandardVO;
import com.example.csmall.commons.pojo.vo.PageData;
import cn.tedu.csmall.passport.security.AdminDetails;
import cn.tedu.csmall.passport.service.IAdminService;
import com.example.csmall.commons.util.PageInfoToPageDataConverter;
import com.example.csmall.commons.web.ServiceCode;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.*;

@Slf4j
@Service
public class AdminServiceImpl implements IAdminService {

    @Value("${csmall.jwt.secret-key}")
    private String secretKey;
    @Value("${csmall.jwt.duration-in-minute}")
    private Long durationInMinute;

    @Autowired
    private AdminMapper adminMapper;
    @Autowired
    private AdminRoleMapper adminRoleMapper;
    @Autowired
    private LoginLogMapper loginLogMapper;
    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private AuthenticationManager authenticationManager;

    @Override
    public String login(AdminLoginInfoParam adminLoginInfoParam) {
        log.debug("开始处理【管理员登录】的业务，参数：{}", adminLoginInfoParam);
        // 创建认证时所需的参数对象
        Authentication authentication = new UsernamePasswordAuthenticationToken(
                adminLoginInfoParam.getUsername(), adminLoginInfoParam.getPassword());
        // 执行认证后获取认证结果的返回值对象
        Authentication authenticationResult = authenticationManager.authenticate(authentication);
        log.debug("验证登录完成，认证结果：{}", authenticationResult);

        // 从认证结果中取出所需的数据
        Object principal = authenticationResult.getPrincipal();
        AdminDetails adminDetails = (AdminDetails) principal;
        Collection<GrantedAuthority> authorities = adminDetails.getAuthorities();

        //生成JWT
        Map<String, Object> claims = new HashMap<>();
        claims.put("id", adminDetails.getId());
        claims.put("username", adminDetails.getUsername());
        claims.put("authoritiesJsonString", JSON.toJSONString(authorities));
        String jwt = Jwts.builder()
                // Header
                .setHeaderParam("alg", "HS256")
                .setHeaderParam("typ", "JWT")
                // Payload
                .setClaims(claims)
                .setExpiration(new Date(System.currentTimeMillis() + durationInMinute * 1000 * 60))
                // Verify Signature
                .signWith(SignatureAlgorithm.HS256, secretKey)
                // 生成
                .compact();
        log.debug("生成了此管理员的信息对应的JWT：{}", jwt);
        return jwt;

        // ===== 使用JWT后不再需要以下2行代码 =====
        // 将认证结果存入到SecurityContext中
//        SecurityContext securityContext = SecurityContextHolder.getContext();
//        securityContext.setAuthentication(authenticationResult);
    }

    @Override
    public void addNew(AdminAddNewParam adminAddNewParam) {
        log.debug("开始处理【添加管理员用户】的业务，参数：{}", adminAddNewParam);
        // 检查用户名是否被占用，如果被占用，则抛出异常
        QueryWrapper<Admin> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("username", adminAddNewParam.getUsername());
        int countByUserName = adminMapper.selectCount(queryWrapper);
        log.debug("根据管理员用户名称统计匹配的用户数量，结果：{}", countByUserName);
        if (countByUserName > 0) {
            String message = "添加用户失败，管理员用户名已存在！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
        }

        // 检查手机号码是否被占用，如果被占用，则抛出异常
        QueryWrapper<Admin> queryWrapper2 = new QueryWrapper<>();
        queryWrapper2.eq("phone", adminAddNewParam.getPhone());
        int countByPhone = adminMapper.selectCount(queryWrapper2);
        log.debug("根据管理员手机号统计匹配的用户数量，结果：{}", countByPhone);
        if (countByPhone > 0) {
            String message = "添加用户失败，管理员用户手机号已存在！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
        }

        // 检查电子邮箱是否被占用，如果被占用，则抛出异常
        QueryWrapper<Admin> queryWrapper3 = new QueryWrapper<>();
        queryWrapper3.eq("email", adminAddNewParam.getEmail());
        int countByEmail = adminMapper.selectCount(queryWrapper3);
        log.debug("根据管理员电子邮箱统计匹配的用户数量，结果：{}", countByEmail);
        if (countByEmail > 0) {
            String message = "添加用户失败，管理员用户电子邮箱已存在！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
        }

        // 将用户添加到数据库中
        Admin admin = new Admin();
        BeanUtils.copyProperties(adminAddNewParam, admin);
        admin.setPassword(passwordEncoder.encode(adminAddNewParam.getPassword()));  //密码加密处理
        admin.setLastLoginIp(null);
        // 添加登录数量统计为0是为了后期累计增加
        admin.setLoginCount(0);
        admin.setGmtLastLogin(null);
        admin.setGmtCreate(LocalDateTime.now());
        admin.setGmtModified(LocalDateTime.now());
        int rows = adminMapper.insert(admin);
        if (rows != 1) {
            String message = "添加管理员失败，服务器忙，请稍后再试！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_INSERT, message);
        }
        log.debug("将新管理员用户添加到数据库中完成");

        // 将管理员与角色的关联写入到数据库中
        Long[] roleIds = adminAddNewParam.getRoleIds();
        AdminRole[] adminRoleList = new AdminRole[roleIds.length];
        LocalDateTime now = LocalDateTime.now();
        for (int i = 0; i < adminRoleList.length; i++) {
            AdminRole adminRole = new AdminRole();
            adminRole.setAdminId(admin.getId());
            adminRole.setRoleId(roleIds[i]);
            adminRole.setGmtCreate(now);
            adminRole.setGmtModified(now);
            adminRoleList[i] = adminRole;
        }
        rows = adminRoleMapper.insertBatch(adminRoleList);
        if (rows != adminRoleList.length) {
            String message = "添加管理员失败，服务器忙，请稍后再试！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_INSERT, message);
        }
        log.debug("将新的管理员与角色的关联数据插入到数据库，完成！");
    }

    @Override
    public void delete(Long id)                                                                  {
        log.debug("开始处理【根据ID删除管理员】的业务,参数:{}", id);
        // 检查该ID是否有对应的管理员
        QueryWrapper<Admin> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("id", id);
        int countById = adminMapper.selectCount(queryWrapper);
        log.debug("根据管理员ID统计匹配的管理员数量,结果:{}", countById);
        if (countById == 0) {
            String message = "删除管理员失败，该管理员ID不存在！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }

        // 检查是否有管理员与角色的关联数据关联到此管理员，如果有则同步删除
        QueryWrapper<AdminRole> queryWrapper1 = new QueryWrapper<>();
        queryWrapper1.eq("admin_id", id);
        int countByAdminId1 = adminRoleMapper.selectCount(queryWrapper1);
        log.debug("根据管理员ID统计匹配的管理员与角色关联数据的数量,结果:{}", countByAdminId1);
        if (countByAdminId1 > 0) {
            log.debug("开始删除管理员与角色关联数据, admin_id:" + id);
            adminRoleMapper.deleteByAdminId(id);
            log.debug("根据管理员ID删除管理员与角色关联数据完成!");
        }

        // 检查是否有管理员登录日志关联到此管理员，如果存在则同步删除
        QueryWrapper<LoginLog> queryWrapper2 = new QueryWrapper<>();
        queryWrapper2.eq("admin_id", id);
        int countByAdminId2 = loginLogMapper.selectCount(queryWrapper2);
        log.debug("根据管理员ID统计匹配的管理员登录日志的数量,结果:{}", countByAdminId2);
        if (countByAdminId2 > 0) {
            log.debug("开始删除管理员登录日志, admin_id:" + id);
            int rows = loginLogMapper.delteByAdminId(id);
            if (rows != 1) {
                String message = "删除管理员登录日志失败，服务器忙，请稍后再试！";
                log.warn(message);
                throw new ServiceException(ServiceCode.ERR_DELETE, message);
            }
            log.debug("根据管理员ID删除登录日志完成!");
        }

        // 执行删除管理员
        log.debug("开始删除管理员, ID:" + id);
        int rows = adminMapper.deleteById(id);
        if (rows != 1) {
            String message = "删除管理员失败，服务器忙，请稍后再试！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_DELETE, message);
        }
        log.debug("根据ID删除管理员完成!");
    }

    @Override
    public AdminStandardVO getStandardById(Long id) {
        log.debug("开始处理【根据ID查询管理员详情】的业务，参数：{}", id);
        AdminStandardVO queryResult = adminMapper.getStandardById(id);
        if (queryResult == null) {
            String message = "根据ID查询管理员详情失败, 该管理员不存在!";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }
        return queryResult;
    }

    @Override
    public void updateInfoById(Long id , AdminUpdateInfoParam adminUpdateInfoParam)       {
        log.debug("开始处理【修改管理员详情】的业务，修改管理员ID参数:{}，新数据：{}", id, adminUpdateInfoParam);
        // 检查该ID是否有对应的管理员
        QueryWrapper<Admin> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("id", id);
        int countById = adminMapper.selectCount(queryWrapper);
        if(countById == 0) {
            String message = "修改管理员详情失败, 该管理员不存在!";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }

        // 检查管理员名称是否与其他管理员冲突，如果冲突抛出异常
        QueryWrapper<Admin> queryWrapper2 = new QueryWrapper<>();
        queryWrapper2.eq("username", adminUpdateInfoParam.getUsername()).ne("id", id);
        int countByUserName = adminMapper.selectCount(queryWrapper2);
        log.debug("根据管理员名称统计匹配的管理员数量，结果：{}", countByUserName);
        if (countByUserName > 0) {
            String message = "修改管理员详情失败，管理员名称已经被占用！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
        }
        // 检查手机号码是否被占用，如果被占用，则抛出异常
        QueryWrapper<Admin> queryWrapper3 = new QueryWrapper<>();
        queryWrapper3.eq("phone", adminUpdateInfoParam.getPhone());
        int countByPhone = adminMapper.selectCount(queryWrapper3);
        log.debug("根据管理员手机号统计匹配的用户数量，结果：{}", countByPhone);
        if (countByPhone > 0) {
            String message = "修改管理员详情失败，管理员用户手机号已存在！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
        }
        // 检查电子邮箱是否被占用，如果被占用，则抛出异常
        QueryWrapper<Admin> queryWrapper4 = new QueryWrapper<>();
        queryWrapper4.eq("email", adminUpdateInfoParam.getEmail());
        int countByEmail = adminMapper.selectCount(queryWrapper4);
        log.debug("根据管理员电子邮箱统计匹配的用户数量，结果：{}", countByEmail);
        if (countByEmail > 0) {
            String message = "修改管理员详情失败，管理员用户电子邮箱已存在！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
        }

        // 执行修改
        log.debug("开始修改管理员{}的详情，新参数：{}", id, adminUpdateInfoParam);
        Admin admin = new Admin();
        BeanUtils.copyProperties(adminUpdateInfoParam, admin);
        admin.setId(id);
        int rows = adminMapper.updateById(admin);
        if (rows != 1) {
            String message = "修改管理员失败，服务器忙，请稍后再试！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_UPDATE, message);
        }
        log.debug("修改管理员详情完成！");
    }

    @Override
    public PageData<AdminListItemVO> list(Integer pageNum) {
        Integer pageSize = 5;
        return list(pageNum, pageSize);
    }

    @Override
    public PageData<AdminListItemVO> list(Integer pageNum, Integer pageSize) {
        log.debug("开始处【查询管理员列表】业务，页码：{}，每页记录数：{}", pageNum, pageSize);
        PageHelper.startPage(pageNum, pageSize);
        List<AdminListItemVO> list = adminMapper.list();
        PageInfo<AdminListItemVO> pageInfo = new PageInfo<>(list);
        PageData<AdminListItemVO> pageData = PageInfoToPageDataConverter.convert(pageInfo);
        log.debug("查询完成，即将返回：{}", pageData);
        return pageData;
    }
}
